package cn.com.bsoft.immunity.utils

import cn.com.bsoft.immunity.kotlin.javaType
import cn.com.bsoft.immunity.kotlin.json
import cn.com.bsoft.immunity.kotlin.json2obj
import cn.com.bsoft.immunity.model.ConstValue
import cn.com.bsoft.immunity.kotlin.sha265
import cn.net.xyan.blossom.kotlin.ErrorRsp
import com.fasterxml.jackson.databind.JavaType
import org.apache.http.HttpHeaders
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.utils.URIBuilder
import org.apache.http.entity.ByteArrayEntity
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClients
import org.apache.http.util.EntityUtils
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.io.OutputStream
import java.net.URL
import java.nio.charset.Charset


//const val secret = "%z#]J+2@)lxAOhY(6YVC"
const val secret = "Ke9Es(8M7W!I0JKp*LC+"
const val partner = "jkw"

//const val secret = "(yGuOnJy>b#=qNz%K3[P"
//const val partner = "12071"

fun URL.post(body: (out: OutputStream) -> Unit,
             initHandler: ((httpPost: HttpPost) -> Unit)? = null): InputStream {
    val byteArrayOutputStream = ByteArrayOutputStream()

    body(byteArrayOutputStream)

    byteArrayOutputStream.flush()

    val httPost = HttpPost(this.toURI())
    val entity = ByteArrayEntity(byteArrayOutputStream.toByteArray())
    httPost.entity = entity

    if (initHandler != null) initHandler(httPost)

    return HttpUtils.httpClient().use {
        httpClient ->
        httpClient.execute(httPost).use {
            response ->
            val responseEntity = response.entity
            if (response.statusLine.statusCode > 400) {
                val msg = EntityUtils.toString(responseEntity)
                println("msg:$msg")
                val rsp: ErrorRsp = msg.json2obj(ErrorRsp::class.javaType)

                println(rsp.traceStack)
                throw rsp.toError()
            }else {
                val bytes = EntityUtils.toByteArray(responseEntity)
                println(String(bytes,Charsets.UTF_8))
                ByteArrayInputStream(bytes)
            }

        }
    }
}

fun URL.get(initHandler: ((httpGet: HttpGet) -> Unit)?): InputStream {
    val httGet = HttpGet(this.toURI())
    if (initHandler != null) initHandler(httGet)

    return HttpUtils.httpClient().use {
        httpClient ->
        httpClient.execute(httGet).use {
            response ->
            val responseEntity = response.entity
            ByteArrayInputStream(EntityUtils.toByteArray(responseEntity))
        }
    }
}

fun <T> URL.postJson(obj: Any, rspType: JavaType): T? {
    return postJson(obj, rspType, {})
}

fun <T> URL.postJson(obj: Any, rspType: JavaType,
                     initHandler: ((httpPost: HttpPost) -> Unit)): T? {
    val charSet = Charset.forName("UTF-8")
    val postBody = obj.json.toByteArray(charSet)
    val sha256 = postBody.sha265(secret.toByteArray(Charsets.ISO_8859_1))
    val content = post({ out ->
        out.write(postBody)
    }, { httpPost: HttpPost ->
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=${charSet.displayName()}")
        //httpPost.setHeader(ConstValue.KeyHeaderPartnerCode, partner)
        //httpPost.setHeader(ConstValue.KeyHeaderSign, sha256)

        var uri = httpPost.uri

        uri = URIBuilder(uri)
                .addParameter(ConstValue.KeyParameterPartnerCode, partner)
                .addParameter(ConstValue.KeyParameterSign, sha256)
                //.addParameter(ConstValue.KeyParameterAlgorithm,"MD5")
                .build()

        println("request uri:$uri")
        println("postBody:${obj.json}")
        println("partner:$partner")
        println("secret:$secret")
        println("sign:$sha256")
        httpPost.uri = uri
        initHandler(httpPost)
    })
    return content.json2obj(rspType)
}

class HttpUtils {
    companion object {
        @JvmStatic
        fun httpClient(): CloseableHttpClient {
            return HttpClients.createDefault()
        }
    }
}